{-------------------------------------------------------------------------------
  Author: Duo (iamduo@qq.com)
  DateTime: 2022/4/12 14:09:16

  yykAuto
-------------------------------------------------------------------------------}
unit uYiYaData_Auto;

interface

uses SysUtils, uYiYaConnParams, uBizDBIntf, Classes;

type
  TYiYaData_Auto = class(TInterfacedObject, IInterface, IDBQuery, IDBTable)
  private
    FInnerDBData:IDBData;
    FConnParams:TYiYaConnParams;
    FFileName:TFileName;
  protected
    function CreateYiYaConnByFileName(const AFileName:TFileName):IDBConn;
    function CreateSqliteDBDataByFileName(const AFileName:TFileName):IDBData;
  public
    constructor Create(const AConnParams: TYiYaConnParams);
    destructor Destroy;override;
    { IInterface }
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    { IDBData }
    procedure Open;
    procedure Append;
    procedure Edit;
    procedure Post;
    procedure Delete;
    procedure Cancel;
    procedure Close;
    function Locate(const AKeyFields, AKeyValues: OleVariant): Boolean;
    function Lookup(const AKeyFields, AKeyValues, AResultFields: OleVariant): OleVariant;
    procedure First;
    procedure Next;
    function Eof: Boolean;
    function RecordCount:Integer;
    function FieldCount:Integer;
    function FieldName(const AIndex:Integer):WideString;
    function ValueCount:Integer;
    function ParamCount:Integer;
    function ParamName(const AIndex:Integer):WideString;
    function DisplayValues(const AFieldNames:OleVariant):OleVariant;
    //
    function GetRecNo:Integer;
    procedure SetRecNo(const AValue:Integer);
    function GetFieldValues(const AFieldNames:OleVariant): OleVariant;
    procedure SetFieldValues(const AFieldNames:OleVariant; const AValue: OleVariant);
    function GetParamValues(const AParamNames:OleVariant): OleVariant;
    procedure SetParamValues(const AParamNames:OleVariant; const AValue: OleVariant);
    { IDBQuery }
    function Exec:Integer;
    function GetSQLText:WideString;
    procedure SetSQLText(const AValue:WideString);
    { IDBTable }
    function GetTableName:WideString;
    procedure SetTableName(const AValue:WideString);
  end;

implementation

uses uDuo.FileEx, uBizYiYaIntf, uDuo.TypInfoEx, uYiYaConn, uDBConn_Sqlite;

type
  TFileExtMap = record
    Kind:string;
    Exts:TArray<string>;
  end;

const
  FILE_EXT_MAPS : array [0..6] of TFileExtMap = (
    (Kind : 'yykCsvFile'   ; Exts : ['csv' , 'txt']),
    (Kind : 'yykXmlFile'   ; Exts : ['xml']),
    (Kind : 'yykCfgFile'   ; Exts : ['cfg']),
    (Kind : 'yykJsonFile'  ; Exts : ['json']),
    (Kind : 'yykFmtFile'   ; Exts : ['fds' , 'fdb' , 'adb', 'json']),
    (Kind : 'yykCdsFile'   ; Exts : ['cds']),
    (Kind : 'yykExcelFile' ; Exts : ['xls', 'xlsx'])
  );

  S_SQLITE_EXTS = 'sqlite,sdb,db3,sdb3,s3db';

{ TYiYaData_Auto }

procedure TYiYaData_Auto.Append;
begin
  FInnerDBData.Append;
end;

procedure TYiYaData_Auto.Cancel;
begin
  FInnerDBData.Cancel;
end;

procedure TYiYaData_Auto.Close;
begin
  FInnerDBData.Close;
end;

constructor TYiYaData_Auto.Create(const AConnParams: TYiYaConnParams);
begin
  FConnParams := AConnParams;
end;

function TYiYaData_Auto.CreateSqliteDBDataByFileName(
  const AFileName: TFileName): IDBData;
var
  sExt:string;
  i:Integer;
  sqliteExts:TArray<string>;
  tempConn:IDBConn;
  table:IDBTable;
  sl:TStringList;
begin
  Result := nil;
  sExt := ExtractFileExt(AFileName).ToLower;
  if sExt.StartsWith('.') then
    sExt := sExt.Remove(0, 1) ;
  sqliteExts := S_SQLITE_EXTS.Split([',']);
  for i := 0 to High(sqliteExts) do
  begin
    if sExt = sqliteExts[i] then
    begin
      tempConn := TDBConn_SQLITE.Create as IDBConn;
      tempConn.ConnString := AFileName;
      sl := TStringList.Create;
      try
        sl.DelimitedText := (tempConn as IDBConnGetNames).GetTableNames;
        if sl.Count > 0 then
        begin
          table := tempConn as IDBTable;
          table.TableName := sl[0];
          Result := table;
        end;
      finally
        sl.Free;
      end;
      Exit;
    end;
  end;
end;

function TYiYaData_Auto.CreateYiYaConnByFileName(
  const AFileName: TFileName): IDBConn;
var
  sExt:string;
  map:TFileExtMap;
  iDepth: Integer;
  i: Integer;
  tempConnParams:TYiYaConnParams;
begin
  Result := nil;
  sExt := ExtractFileExt(AFileName).ToLower;
  if sExt.StartsWith('.') then
    sExt := sExt.Remove(0, 1) ;
  for iDepth := 0 to 3 do
  begin
    for i := 0 to High(FILE_EXT_MAPS) do
    begin
      map := FILE_EXT_MAPS[i];
      if iDepth <= High(map.Exts) then
      begin
        if sExt = map.Exts[iDepth] then
        begin
          Result := TYiYaConn.Create as IDBConn;
          tempConnParams := FConnParams;
          tempConnParams.Kind := Type_FromString(TypeInfo(TYiYaKind), map.Kind, 0);
          Result.ConnString := tempConnParams.AsConnString;
          Exit;
        end;
      end;
    end;
  end;
end;

procedure TYiYaData_Auto.Delete;
begin
  FInnerDBData.Delete;
end;

destructor TYiYaData_Auto.Destroy;
begin
  FInnerDBData := nil;
  inherited;
end;

function TYiYaData_Auto.DisplayValues(
  const AFieldNames: OleVariant): OleVariant;
begin
  Result := FInnerDBData.DisplayValues(AFieldNames);
end;

procedure TYiYaData_Auto.Edit;
begin
  FInnerDBData.Edit;
end;

function TYiYaData_Auto.Eof: Boolean;
begin
  Result := FInnerDBData.Eof;
end;

function TYiYaData_Auto.Exec: Integer;
var
  query:IDBQuery;
begin
  if Supports(FInnerDBData, IDBQuery, query) then
    Result := query.Exec
  else
    Result := 0;
end;

function TYiYaData_Auto.FieldCount: Integer;
begin
  Result := FInnerDBData.FieldCount;
end;

function TYiYaData_Auto.FieldName(const AIndex: Integer): WideString;
begin
  Result := FInnerDBData.FieldName(AIndex);
end;

procedure TYiYaData_Auto.First;
begin
  FInnerDBData.First;
end;

function TYiYaData_Auto.GetFieldValues(
  const AFieldNames: OleVariant): OleVariant;
begin
  Result := FInnerDBData.GetFieldValues(AFieldNames);
end;

function TYiYaData_Auto.GetParamValues(
  const AParamNames: OleVariant): OleVariant;
begin
  Result := FInnerDBData.GetParamValues(AParamNames);
end;

function TYiYaData_Auto.GetRecNo: Integer;
begin
  Result := FInnerDBData.GetRecNo;
end;

function TYiYaData_Auto.GetSQLText: WideString;
begin
  Result := File_ShortName(FFileName);
end;

function TYiYaData_Auto.GetTableName: WideString;
begin
  Result := File_ShortName(FConnParams.Folder, FFileName);
end;

function TYiYaData_Auto.Locate(const AKeyFields,
  AKeyValues: OleVariant): Boolean;
begin
  Result := FInnerDBData.Locate(AKeyFields, AKeyValues);
end;

function TYiYaData_Auto.Lookup(const AKeyFields, AKeyValues,
  AResultFields: OleVariant): OleVariant;
begin
  Result := FInnerDBData.Lookup(AKeyFields, AKeyValues, AResultFields);
end;

procedure TYiYaData_Auto.Next;
begin
  FInnerDBData.Next;
end;

procedure TYiYaData_Auto.Open;
begin
  FInnerDBData.Open;
end;

function TYiYaData_Auto.ParamCount: Integer;
begin
  Result := FInnerDBData.ParamCount;
end;

function TYiYaData_Auto.ParamName(const AIndex: Integer): WideString;
begin
  Result := FInnerDBData.ParamName(AIndex);
end;

procedure TYiYaData_Auto.Post;
begin
  FInnerDBData.Post;
end;

function TYiYaData_Auto.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  Result := inherited QueryInterface(IID, Obj);
  if Result <> S_OK then
  begin
    if Supports(FInnerDBData, IID, Obj) then
      Result := S_OK;
  end;
end;

function TYiYaData_Auto.RecordCount: Integer;
begin
  Result := FInnerDBData.RecordCount;
end;

procedure TYiYaData_Auto.SetFieldValues(const AFieldNames, AValue: OleVariant);
begin
  FInnerDBData.SetFieldValues(AFieldNames, AValue);
end;

procedure TYiYaData_Auto.SetParamValues(const AParamNames, AValue: OleVariant);
begin
  FInnerDBData.SetParamValues(AParamNames, AValue);
end;

procedure TYiYaData_Auto.SetRecNo(const AValue: Integer);
begin
  FInnerDBData.SetRecNo(AValue);
end;

procedure TYiYaData_Auto.SetSQLText(const AValue: WideString);
var
  conn:IDBConn;
  query:IDBQuery;
begin
  FFileName := File_FullName(AValue);
  conn := CreateYiYaConnByFileName(FFileName);
  if conn <> nil then
  begin
    query := conn as IDBQuery;
    query.SQLText := AValue;
    FInnerDBData := query;
  end
  else
    FInnerDBData := CreateSqliteDBDataByFileName(FFileName);
end;

procedure TYiYaData_Auto.SetTableName(const AValue: WideString);
var
  conn:IDBConn;
  table:IDBTable;
begin
  FFileName := File_NameEncode(FConnParams.Folder, trim(AValue));
  conn := CreateYiYaConnByFileName(FFileName);
  if conn <> nil then
  begin
    table := conn as IDBTable;
    table.TableName := AValue;
    FInnerDBData := table;
  end
  else
    FInnerDBData := CreateSqliteDBDataByFileName(FFileName);
end;

function TYiYaData_Auto.ValueCount: Integer;
begin
  Result := FInnerDBData.ValueCount;
end;

end.
